{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "code",
      "source": [
        "!pip install -Uq openai-agents langchain-community chromadb \"openai-agents[litellm]\" langchain-openai\n",
        "!pip install pypdf"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "3ILJmVi4zniH",
        "outputId": "d77a1043-cfb3-4bd9-86de-00180b2f68f4"
      },
      "execution_count": 9,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[?25l   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m0.0/2.5 MB\u001b[0m \u001b[31m?\u001b[0m eta \u001b[36m-:--:--\u001b[0m\r\u001b[2K   \u001b[91m━━━━━━━━━━━━\u001b[0m\u001b[90m╺\u001b[0m\u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m0.8/2.5 MB\u001b[0m \u001b[31m22.6 MB/s\u001b[0m eta \u001b[36m0:00:01\u001b[0m\r\u001b[2K   \u001b[91m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[91m╸\u001b[0m \u001b[32m2.5/2.5 MB\u001b[0m \u001b[31m42.4 MB/s\u001b[0m eta \u001b[36m0:00:01\u001b[0m\r\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.5/2.5 MB\u001b[0m \u001b[31m28.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m63.4/63.4 kB\u001b[0m \u001b[31m3.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m438.3/438.3 kB\u001b[0m \u001b[31m20.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m50.9/50.9 kB\u001b[0m \u001b[31m2.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hCollecting pypdf\n",
            "  Downloading pypdf-5.5.0-py3-none-any.whl.metadata (7.2 kB)\n",
            "Downloading pypdf-5.5.0-py3-none-any.whl (303 kB)\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m303.4/303.4 kB\u001b[0m \u001b[31m4.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25hInstalling collected packages: pypdf\n",
            "Successfully installed pypdf-5.5.0\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "from google.colab import userdata\n",
        "import os\n",
        "os.environ[\"GEMINI_API_KEY\"] = userdata.get('GEMINI_API_KEY')"
      ],
      "metadata": {
        "id": "GhFV4Yqy1Htz"
      },
      "execution_count": 10,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "import nest_asyncio\n",
        "nest_asyncio.apply()"
      ],
      "metadata": {
        "id": "V7dQ3pdI1P0a"
      },
      "execution_count": 11,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "!pip install -Uq openai-agents langchain-community chromadb \"openai-agents[litellm]\" langchain-openai langchain-google-genai"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "vdSFRx7jche7",
        "outputId": "796cde21-21a4-472d-e560-c0dae94ed355"
      },
      "execution_count": 12,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m44.3/44.3 kB\u001b[0m \u001b[31m1.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.4/1.4 MB\u001b[0m \u001b[31m18.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
            "\u001b[?25h\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n",
            "google-generativeai 0.8.5 requires google-ai-generativelanguage==0.6.15, but you have google-ai-generativelanguage 0.6.18 which is incompatible.\u001b[0m\u001b[31m\n",
            "\u001b[0m"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "-pefwf36pDeU"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "!pip install -Uq openai-agents chromadb google-genai\n"
      ],
      "metadata": {
        "id": "rKoogccfpDjc"
      },
      "execution_count": 14,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "import os\n",
        "from google.colab import userdata\n",
        "\n",
        "# Set your API keys (replace the placeholders with your actual keys)\n",
        "# os.environ[\"OPENAI_API_KEY\"] = \"sk-...\"            # OpenAI API key for Agents SDK\n",
        "GEMINI_API_KEY = userdata.get(\"GEMINI_API_KEY\")       # Google Gemini API key\n",
        "\n",
        "# Import the necessary classes\n",
        "from agents import Agent, Runner, function_tool   # OpenAI Agents SDK components\n",
        "import chromadb                                   # ChromaDB client\n",
        "from chromadb.utils import embedding_functions    # (optional, if using embedding functions directly)\n",
        "from google import genai                          # Google GenAI SDK for Gemini\n",
        "from google.genai.types import EmbedContentConfig\n"
      ],
      "metadata": {
        "id": "H9ac_n7szsFI"
      },
      "execution_count": 36,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Initialize ChromaDB in-memory client\n",
        "chroma_client = chromadb.Client()  # default uses an in-memory SQLite store\n",
        "\n",
        "# Initialize Google GenAI client with the Gemini API key\n",
        "client = genai.Client(api_key=GEMINI_API_KEY)\n"
      ],
      "metadata": {
        "id": "b4iMI2WHpko4"
      },
      "execution_count": 37,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Define a few short text documents (e.g., Wikipedia-style snippets)\n",
        "documents = [\n",
        "    \"Cats are small, domesticated carnivorous mammals often valued by humans for companionship and for their ability to hunt vermin.\",\n",
        "    \"Dogs are domesticated mammals, not natural wild animals. They were originally bred from wolves.\",\n",
        "    \"The Apollo program was a series of space missions by NASA in the 1960s and 1970s aimed at landing humans on the Moon.\"\n",
        "]\n",
        "doc_ids = [\"doc1\", \"doc2\", \"doc3\"]\n",
        "\n",
        "# (Optional) Print the documents to verify\n",
        "for i, doc in enumerate(documents, 1):\n",
        "    print(f\"Document {i}: {doc[:60]}...\")\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "-GOwmIFHpnCp",
        "outputId": "858fe02a-ff53-423e-d658-11c14810101d"
      },
      "execution_count": 38,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Document 1: Cats are small, domesticated carnivorous mammals often value...\n",
            "Document 2: Dogs are domesticated mammals, not natural wild animals. The...\n",
            "Document 3: The Apollo program was a series of space missions by NASA in...\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Embed each document using the Gemini embedding model\n",
        "embed_model = \"gemini-embedding-exp-03-07\"\n",
        "\n",
        "# Generate embeddings for all documents in one call\n",
        "response = client.models.embed_content(\n",
        "    model=embed_model,\n",
        "    contents=documents,\n",
        "    config=EmbedContentConfig(task_type=\"RETRIEVAL_DOCUMENT\")  # optimize embeddings for retrieval\n",
        ")\n",
        "\n",
        "# Extract the embedding vectors from the response\n",
        "doc_embeddings = [emb.values for emb in response.embeddings]\n",
        "\n",
        "# Check the number of embeddings and dimensionality of one embedding\n",
        "print(f\"Generated {len(doc_embeddings)} embeddings.\")\n",
        "print(f\"Dimension of first embedding: {len(doc_embeddings[0])}\")\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ycCnO1Tup0k6",
        "outputId": "a900b5a3-3e18-452f-a389-19f08d2fb480"
      },
      "execution_count": 39,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Generated 3 embeddings.\n",
            "Dimension of first embedding: 3072\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "print(f\"Sample of first embedding vector: {doc_embeddings[0][:5]}...\")  # print first 5 values\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "nYQG8AsJp1S6",
        "outputId": "54ad45ef-8757-48bb-d58f-08ad62d2ba0c"
      },
      "execution_count": 40,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Sample of first embedding vector: [-0.02342979, 0.018499875, 0.012728111, -0.045184404, 0.0019269326]...\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Create a ChromaDB collection for our documents\n",
        "collection = chroma_client.create_collection(name=\"knowledge_base\")\n",
        "\n",
        "# Add documents, their embeddings, and IDs to the collection\n",
        "collection.add(\n",
        "    documents=documents,\n",
        "    embeddings=doc_embeddings,\n",
        "    ids=doc_ids\n",
        ")\n",
        "\n",
        "# (Optional) verify collection size\n",
        "print(\"Documents in collection:\", collection.count())\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "e8GJ-Abrp4Ym",
        "outputId": "97c9b22f-8e30-4e4f-b8a1-17dc01a13509"
      },
      "execution_count": 42,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Documents in collection: 3\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# User's question\n",
        "user_question = \"What was the goal of the Apollo program?\"\n",
        "\n",
        "# Embed the user query using the same model (use task_type RETRIEVAL_QUERY for queries)\n",
        "query_response = client.models.embed_content(\n",
        "    model=embed_model,\n",
        "    contents=[user_question],\n",
        "    config=EmbedContentConfig(task_type=\"RETRIEVAL_QUERY\")\n",
        ")\n",
        "query_vector = query_response.embeddings[0].values\n",
        "# query_vector\n",
        "\n",
        "# Use ChromaDB to find the most similar document(s) to the query\n",
        "results = collection.query(\n",
        "    query_embeddings=[query_vector],\n",
        "    n_results=2,  # fetch top 2 most similar docs\n",
        "    # Remove 'ids' from the include list as it's not a valid option\n",
        "    include=[\"documents\", \"distances\"]\n",
        ")\n",
        "results\n",
        "\n",
        "# Print out the retrieved documents and their similarity scores\n",
        "# print(\"Query:\", user_question)\n",
        "# for doc, score, doc_id in zip(results[\"documents\"][0], results[\"distances\"][0], results[\"ids\"][0]):\n",
        "#     print(f\"- Retrieved {doc_id} with similarity score {score:.4f}: {doc[:60]}...\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ArIp4hp4p7Ae",
        "outputId": "aa7ffb1c-3b86-442f-fd9c-d3fbb7dc6aff"
      },
      "execution_count": 43,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "{'ids': [['doc3', 'doc2']],\n",
              " 'embeddings': None,\n",
              " 'documents': [['The Apollo program was a series of space missions by NASA in the 1960s and 1970s aimed at landing humans on the Moon.',\n",
              "   'Dogs are domesticated mammals, not natural wild animals. They were originally bred from wolves.']],\n",
              " 'uris': None,\n",
              " 'included': ['documents', 'distances'],\n",
              " 'data': None,\n",
              " 'metadatas': None,\n",
              " 'distances': [[0.4427131414413452, 0.9165204763412476]]}"
            ]
          },
          "metadata": {},
          "execution_count": 43
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "print(f\"Sample of first embedding vector: {doc_embeddings[0][:5]}...\")  # print first 5 values\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "7SspTvN-p-lp",
        "outputId": "a09690f8-dab2-4c2f-bdf3-1e461e421165"
      },
      "execution_count": 44,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Sample of first embedding vector: [-0.02342979, 0.018499875, 0.012728111, -0.045184404, 0.0019269326]...\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Prepare the context from the retrieved docs\n",
        "retrieved_docs = results[\"documents\"][0]\n",
        "context = \"\\n\\n\".join(retrieved_docs)\n",
        "\n",
        "# Formulate the prompt for the LLM\n",
        "prompt = f\"\"\"Use the following context to answer the question.\n",
        "\n",
        "Context:\n",
        "{context}\n",
        "\n",
        "Question:\n",
        "{user_question}\n",
        "\n",
        "Answer the question using only the information from the context above.\"\"\"\n",
        "print(prompt)\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "KHvyepunspg0",
        "outputId": "d10a80fd-cb7a-4e19-a0e6-c80c3bf1cdae"
      },
      "execution_count": 45,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Use the following context to answer the question.\n",
            "\n",
            "Context:\n",
            "The Apollo program was a series of space missions by NASA in the 1960s and 1970s aimed at landing humans on the Moon.\n",
            "\n",
            "Dogs are domesticated mammals, not natural wild animals. They were originally bred from wolves.\n",
            "\n",
            "Question:\n",
            "What was the goal of the Apollo program?\n",
            "\n",
            "Answer the question using only the information from the context above.\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Use the Gemini 1.5 Flash model to get an answer based on the context\n",
        "response = client.models.generate_content(\n",
        "    model=\"gemini-1.5-flash\",\n",
        "    contents=prompt\n",
        ")\n",
        "answer = response.text\n",
        "\n",
        "print(\"Answer:\", answer)\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "idML1m1psuMH",
        "outputId": "8eb10cee-f0ea-424f-b6aa-52eb4c9165e8"
      },
      "execution_count": 46,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Answer: The goal of the Apollo program was to land humans on the Moon.\n",
            "\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [],
      "metadata": {
        "id": "FoNio_NAt9jC"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "import nest_asyncio\n",
        "nest_asyncio.apply()"
      ],
      "metadata": {
        "id": "09O_c-3xt9z_"
      },
      "execution_count": 47,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "import os\n",
        "from agents import Agent, Runner, AsyncOpenAI, OpenAIChatCompletionsModel\n",
        "from agents.run import RunConfig\n",
        "from google.colab import userdata\n",
        "\n",
        "\n",
        "gemini_api_key = userdata.get(\"GEMINI_API_KEY\")\n",
        "\n",
        "\n",
        "# Check if the API key is present; if not, raise an error\n",
        "if not gemini_api_key:\n",
        "    raise ValueError(\"GEMINI_API_KEY is not set. Please ensure it is defined in your .env file.\")\n",
        "\n",
        "#Reference: https://ai.google.dev/gemini-api/docs/openai\n",
        "external_client = AsyncOpenAI(\n",
        "    api_key=gemini_api_key,\n",
        "    base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\",\n",
        ")\n",
        "\n",
        "model = OpenAIChatCompletionsModel(\n",
        "    model=\"gemini-2.0-flash\",\n",
        "    openai_client=external_client\n",
        ")\n",
        "\n",
        "config = RunConfig(\n",
        "    model=model,\n",
        "    model_provider=external_client,\n",
        "    tracing_disabled=True\n",
        ")"
      ],
      "metadata": {
        "id": "w14gGff8t-ln"
      },
      "execution_count": 48,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "import os\n",
        "from agents import Agent, Runner, AsyncOpenAI, OpenAIChatCompletionsModel, set_default_openai_client, set_tracing_disabled\n",
        "from agents.run import RunConfig\n",
        "from google.colab import userdata\n",
        "\n",
        "set_tracing_disabled(True)\n",
        "gemini_api_key = userdata.get(\"GEMINI_API_KEY\")\n",
        "\n",
        "\n",
        "external_client = AsyncOpenAI(\n",
        "    api_key=gemini_api_key,\n",
        "    base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\",\n",
        ")\n",
        "set_default_openai_client(external_client)"
      ],
      "metadata": {
        "id": "GT7Qr2d1uEiV"
      },
      "execution_count": 49,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "from agents.tool import function_tool"
      ],
      "metadata": {
        "id": "zLH4D9KguFIB"
      },
      "execution_count": 50,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "@function_tool\n",
        "def answer_from_knowledge_base(query: str) -> str:\n",
        "    \"\"\"\n",
        "    Tool: Given a user query, this tool searches the knowledge base and returns an answer using retrieved documents.\n",
        "    \"\"\"\n",
        "    # Embed the query\n",
        "    q_resp = client.models.embed_content(\n",
        "        model=embed_model,\n",
        "        contents=[query],\n",
        "        config=EmbedContentConfig(task_type=\"RETRIEVAL_QUERY\")\n",
        "    )\n",
        "    q_vector = q_resp.embeddings[0].values\n",
        "    # Search the vector store\n",
        "    res = collection.query(query_embeddings=[q_vector], n_results=1, include=[\"documents\"])\n",
        "    top_doc = res[\"documents\"][0][0]  # top result's text\n",
        "    # Construct prompt with retrieved context\n",
        "    prompt = f\"Context:\\n{top_doc}\\n\\nQuestion:\\n{query}\\n\\nAnswer the question using only the context above.\"\n",
        "    # Generate answer with Gemini 1.5 Flash\n",
        "    resp = client.models.generate_content(model=\"gemini-1.5-flash\", contents=prompt)\n",
        "    return resp.text\n"
      ],
      "metadata": {
        "id": "0uw4wh7dsyKZ"
      },
      "execution_count": 51,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "!pip install -Uq openai-agents langchain-community chromadb langchain-openai langchain-google-genai litellm\n"
      ],
      "metadata": {
        "id": "a91srJvwqfvX"
      },
      "execution_count": 52,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Install necessary packages\n",
        "!pip install -Uq openai-agents langchain-community chromadb langchain-openai langchain-google-genai litellm\n",
        "\n",
        "# Import necessary libraries\n",
        "import os\n",
        "import asyncio\n",
        "from agents import Agent, Runner, AsyncOpenAI, OpenAIChatCompletionsModel, set_default_openai_client, set_tracing_disabled, function_tool\n",
        "from google.colab import userdata\n",
        "import chromadb\n",
        "from google import genai\n",
        "from google.genai.types import EmbedContentConfig\n",
        "import nest_asyncio\n",
        "\n",
        "# Apply nest_asyncio for compatibility with notebooks\n",
        "nest_asyncio.apply()\n",
        "\n",
        "# Set up tracing\n",
        "set_tracing_disabled(True)\n",
        "\n",
        "# Get Gemini API key\n",
        "gemini_api_key = userdata.get(\"GEMINI_API_KEY\")\n",
        "if not gemini_api_key:\n",
        "    raise ValueError(\"GEMINI_API_KEY is not set. Please ensure it is defined in your userdata.\")\n",
        "\n",
        "# Configure the OpenAI-compatible client for Gemini\n",
        "external_client = AsyncOpenAI(\n",
        "    api_key=gemini_api_key,\n",
        "    base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\",\n",
        ")\n",
        "\n",
        "# Set this as the default OpenAI client for agents\n",
        "set_default_openai_client(external_client)\n",
        "\n",
        "# Initialize Google GenAI client for RAG embedding/generation\n",
        "client = genai.Client(api_key=gemini_api_key)\n",
        "\n",
        "# Initialize ChromaDB in-memory client\n",
        "chroma_client = chromadb.Client()\n",
        "\n",
        "# Define and embed documents\n",
        "documents = [\n",
        "    \"Cats are small, domesticated carnivorous mammals often valued by humans for companionship and for their ability to hunt vermin.\",\n",
        "    \"Dogs are domesticated mammals, not natural wild animals. They were originally bred from wolves.\",\n",
        "    \"The Apollo program was a series of space missions by NASA in the 1960s and 1970s aimed at landing humans on the Moon.\"\n",
        "]\n",
        "doc_ids = [\"doc1\", \"doc2\", \"doc3\"]\n",
        "embed_model = \"gemini-embedding-exp-03-07\" # Or whichever model you used\n",
        "\n",
        "# Generate embeddings for all documents in one call\n",
        "response = client.models.embed_content(\n",
        "    model=embed_model,\n",
        "    contents=documents,\n",
        "    config=EmbedContentConfig(task_type=\"RETRIEVAL_DOCUMENT\")\n",
        ")\n",
        "doc_embeddings = [emb.values for emb in response.embeddings]\n",
        "\n",
        "# Create or get the collection\n",
        "collection = chroma_client.get_or_create_collection(name=\"knowledge_base1\")\n",
        "\n",
        "# Add documents, handling potential duplicates\n",
        "try:\n",
        "    collection.add(\n",
        "        documents=documents,\n",
        "        embeddings=doc_embeddings,\n",
        "        ids=doc_ids\n",
        "    )\n",
        "except Exception as e:\n",
        "    print(f\"Could not add documents to collection, potentially they already exist: {e}\")\n",
        "\n",
        "\n",
        "# Define the RAG tool using the accessible clients and variables\n",
        "@function_tool\n",
        "def answer_from_knowledge_base(query: str) -> str:\n",
        "    \"\"\"\n",
        "    Tool: Given a user query, this tool searches the knowledge base and returns an answer using retrieved documents.\n",
        "    \"\"\"\n",
        "    print(f\"[Debug] RAG function call with query {query}\")\n",
        "    # Embed the query using the accessible 'client' and 'embed_model'\n",
        "    q_resp = client.models.embed_content(\n",
        "        model=embed_model,\n",
        "        contents=[query],\n",
        "        config=EmbedContentConfig(task_type=\"RETRIEVAL_QUERY\")\n",
        "    )\n",
        "    q_vector = q_resp.embeddings[0].values\n",
        "    # Search the vector store using the accessible 'collection'\n",
        "    res = collection.query(query_embeddings=[q_vector], n_results=1, include=[\"documents\"])\n",
        "    print(f\"[Debug] RAG vector db output {res}\")\n",
        "    # Check if any documents were returned\n",
        "    if res and res.get(\"documents\") and res[\"documents\"][0]:\n",
        "        top_doc = res[\"documents\"][0][0]  # top result's text\n",
        "        # Construct prompt with retrieved context\n",
        "        prompt = f\"Context:\\n{top_doc}\\n\\nQuestion:\\n{query}\\n\\nAnswer the question using only the context above.\"\n",
        "        # Generate answer with Gemini 1.5 Flash using the accessible 'client'\n",
        "        resp = client.models.generate_content(model=\"gemini-1.5-flash\", contents=prompt)\n",
        "        print(f\"[Debug] RAG function call with response ***{resp.text}***\")\n",
        "        return resp.text\n",
        "    else:\n",
        "        return \"Could not find relevant information in the knowledge base.\"\n",
        "\n",
        "# Create an agent that can use the knowledge base tool\n",
        "# Use OpenAIChatCompletionsModel with the external_client\n",
        "qa_agent = Agent(\n",
        "    name=\"QA Agent\",\n",
        "    instructions=\"You are a helpful assistant. If the user asks a question, use your tools to find information in the knowledge base and answer with that information.\",\n",
        "    tools=[answer_from_knowledge_base],\n",
        "    # Use OpenAIChatCompletionsModel with the pre-configured external_client\n",
        "    model=OpenAIChatCompletionsModel(\n",
        "        model=\"gemini-1.5-flash-001\", # Specify the model name compatible with the OpenAI-like endpoint\n",
        "        openai_client=external_client\n",
        "    )\n",
        ")\n",
        "\n",
        "async def main():\n",
        "    agent_question = \"Which domestic animal was originally bred from wolves? what do you know about Apollo?\"\n",
        "\n",
        "    # Run the agent\n",
        "    result = await Runner.run(qa_agent, agent_question)\n",
        "\n",
        "    # Extract and print the final answer\n",
        "    print(\"Agent result:\", result)\n",
        "    print(\"Agent's answer:\", result.final_output)\n",
        "\n",
        "if __name__ == \"__main__\":\n",
        "    asyncio.run(main())"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "f-kIHzOLs8Vg",
        "outputId": "ea662268-e23a-487c-aebb-ea42bd19fff8"
      },
      "execution_count": 53,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[Debug] RAG function call with query Which domestic animal was originally bred from wolves?\n",
            "[Debug] RAG vector db output {'ids': [['doc2']], 'embeddings': None, 'documents': [['Dogs are domesticated mammals, not natural wild animals. They were originally bred from wolves.']], 'uris': None, 'included': ['documents'], 'data': None, 'metadatas': None, 'distances': None}\n",
            "[Debug] RAG function call with response ***Dogs.\n",
            "***\n",
            "[Debug] RAG function call with query what do you know about Apollo?\n",
            "[Debug] RAG vector db output {'ids': [['doc3']], 'embeddings': None, 'documents': [['The Apollo program was a series of space missions by NASA in the 1960s and 1970s aimed at landing humans on the Moon.']], 'uris': None, 'included': ['documents'], 'data': None, 'metadatas': None, 'distances': None}\n",
            "[Debug] RAG function call with response ***Apollo was a series of NASA space missions in the 1960s and 1970s that aimed to land humans on the Moon.\n",
            "***\n",
            "Agent result: RunResult:\n",
            "- Last agent: Agent(name=\"QA Agent\", ...)\n",
            "- Final output (str):\n",
            "    Apollo was a series of NASA space missions in the 1960s and 1970s that aimed to land humans on the Moon. \n",
            "- 6 new item(s)\n",
            "- 3 raw response(s)\n",
            "- 0 input guardrail result(s)\n",
            "- 0 output guardrail result(s)\n",
            "(See `RunResult` for more details)\n",
            "Agent's answer: Apollo was a series of NASA space missions in the 1960s and 1970s that aimed to land humans on the Moon. \n",
            "\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## With PDF"
      ],
      "metadata": {
        "id": "vGbTDO9qq1hB"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "!pip install pypdf\n",
        "from langchain_community.document_loaders import PyPDFLoader\n",
        "\n",
        "def load_and_split_pdf(file_path: str):\n",
        "  \"\"\"Loads a PDF and splits it into pages.\"\"\"\n",
        "  loader = PyPDFLoader(file_path)\n",
        "  pages = loader.load_and_split()\n",
        "  return pages\n",
        "\n",
        "# Example usage: Upload a PDF and process it\n",
        "from google.colab import files\n",
        "uploaded = files.upload()\n",
        "\n",
        "pdf_file_path = list(uploaded.keys())[0]\n",
        "pdf_pages = load_and_split_pdf(pdf_file_path)\n",
        "\n",
        "print(f\"Loaded {len(pdf_pages)} pages from {pdf_file_path}\")\n",
        "\n",
        "# Extract text content from the pages\n",
        "pdf_documents_text = [page.page_content for page in pdf_pages]\n",
        "pdf_doc_ids = [f\"pdf_page_{i+1}\" for i in range(len(pdf_pages))]\n",
        "\n",
        "# Embed the PDF document content\n",
        "pdf_embeddings_response = client.models.embed_content(\n",
        "    model=embed_model,\n",
        "    contents=pdf_documents_text,\n",
        "    config=EmbedContentConfig(task_type=\"RETRIEVAL_DOCUMENT\")\n",
        ")\n",
        "pdf_doc_embeddings = [emb.values for emb in pdf_embeddings_response.embeddings]\n",
        "\n",
        "# Add the PDF content and embeddings to the ChromaDB collection\n",
        "# Get the existing collection or create a new one if it doesn't exist\n",
        "collection = chroma_client.get_or_create_collection(name=\"knowledge_base1\")\n",
        "\n",
        "try:\n",
        "    collection.add(\n",
        "        documents=pdf_documents_text,\n",
        "        embeddings=pdf_doc_embeddings,\n",
        "        ids=pdf_doc_ids\n",
        "    )\n",
        "    print(f\"Added {len(pdf_pages)} PDF pages to the knowledge base.\")\n",
        "except Exception as e:\n",
        "    print(f\"Could not add PDF documents to collection, potentially they already exist: {e}\")\n",
        "\n",
        "print(\"Total documents in collection:\", collection.count())\n",
        "\n",
        "# The rest of your agent and RAG tool code should work with the updated collection.\n",
        "# You can now ask questions that might be answered by the content of the uploaded PDF.\n"
      ],
      "metadata": {
        "id": "a16HxnL8u-SI",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 145
        },
        "outputId": "5182624a-0185-4e74-c728-5a52d80a8835"
      },
      "execution_count": 54,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Requirement already satisfied: pypdf in /usr/local/lib/python3.11/dist-packages (5.5.0)\n"
          ]
        },
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<IPython.core.display.HTML object>"
            ],
            "text/html": [
              "\n",
              "     <input type=\"file\" id=\"files-42a33e33-77fe-47ca-9f71-e61975f2cd94\" name=\"files[]\" multiple disabled\n",
              "        style=\"border:none\" />\n",
              "     <output id=\"result-42a33e33-77fe-47ca-9f71-e61975f2cd94\">\n",
              "      Upload widget is only available when the cell has been executed in the\n",
              "      current browser session. Please rerun this cell to enable.\n",
              "      </output>\n",
              "      <script>// Copyright 2017 Google LLC\n",
              "//\n",
              "// Licensed under the Apache License, Version 2.0 (the \"License\");\n",
              "// you may not use this file except in compliance with the License.\n",
              "// You may obtain a copy of the License at\n",
              "//\n",
              "//      http://www.apache.org/licenses/LICENSE-2.0\n",
              "//\n",
              "// Unless required by applicable law or agreed to in writing, software\n",
              "// distributed under the License is distributed on an \"AS IS\" BASIS,\n",
              "// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
              "// See the License for the specific language governing permissions and\n",
              "// limitations under the License.\n",
              "\n",
              "/**\n",
              " * @fileoverview Helpers for google.colab Python module.\n",
              " */\n",
              "(function(scope) {\n",
              "function span(text, styleAttributes = {}) {\n",
              "  const element = document.createElement('span');\n",
              "  element.textContent = text;\n",
              "  for (const key of Object.keys(styleAttributes)) {\n",
              "    element.style[key] = styleAttributes[key];\n",
              "  }\n",
              "  return element;\n",
              "}\n",
              "\n",
              "// Max number of bytes which will be uploaded at a time.\n",
              "const MAX_PAYLOAD_SIZE = 100 * 1024;\n",
              "\n",
              "function _uploadFiles(inputId, outputId) {\n",
              "  const steps = uploadFilesStep(inputId, outputId);\n",
              "  const outputElement = document.getElementById(outputId);\n",
              "  // Cache steps on the outputElement to make it available for the next call\n",
              "  // to uploadFilesContinue from Python.\n",
              "  outputElement.steps = steps;\n",
              "\n",
              "  return _uploadFilesContinue(outputId);\n",
              "}\n",
              "\n",
              "// This is roughly an async generator (not supported in the browser yet),\n",
              "// where there are multiple asynchronous steps and the Python side is going\n",
              "// to poll for completion of each step.\n",
              "// This uses a Promise to block the python side on completion of each step,\n",
              "// then passes the result of the previous step as the input to the next step.\n",
              "function _uploadFilesContinue(outputId) {\n",
              "  const outputElement = document.getElementById(outputId);\n",
              "  const steps = outputElement.steps;\n",
              "\n",
              "  const next = steps.next(outputElement.lastPromiseValue);\n",
              "  return Promise.resolve(next.value.promise).then((value) => {\n",
              "    // Cache the last promise value to make it available to the next\n",
              "    // step of the generator.\n",
              "    outputElement.lastPromiseValue = value;\n",
              "    return next.value.response;\n",
              "  });\n",
              "}\n",
              "\n",
              "/**\n",
              " * Generator function which is called between each async step of the upload\n",
              " * process.\n",
              " * @param {string} inputId Element ID of the input file picker element.\n",
              " * @param {string} outputId Element ID of the output display.\n",
              " * @return {!Iterable<!Object>} Iterable of next steps.\n",
              " */\n",
              "function* uploadFilesStep(inputId, outputId) {\n",
              "  const inputElement = document.getElementById(inputId);\n",
              "  inputElement.disabled = false;\n",
              "\n",
              "  const outputElement = document.getElementById(outputId);\n",
              "  outputElement.innerHTML = '';\n",
              "\n",
              "  const pickedPromise = new Promise((resolve) => {\n",
              "    inputElement.addEventListener('change', (e) => {\n",
              "      resolve(e.target.files);\n",
              "    });\n",
              "  });\n",
              "\n",
              "  const cancel = document.createElement('button');\n",
              "  inputElement.parentElement.appendChild(cancel);\n",
              "  cancel.textContent = 'Cancel upload';\n",
              "  const cancelPromise = new Promise((resolve) => {\n",
              "    cancel.onclick = () => {\n",
              "      resolve(null);\n",
              "    };\n",
              "  });\n",
              "\n",
              "  // Wait for the user to pick the files.\n",
              "  const files = yield {\n",
              "    promise: Promise.race([pickedPromise, cancelPromise]),\n",
              "    response: {\n",
              "      action: 'starting',\n",
              "    }\n",
              "  };\n",
              "\n",
              "  cancel.remove();\n",
              "\n",
              "  // Disable the input element since further picks are not allowed.\n",
              "  inputElement.disabled = true;\n",
              "\n",
              "  if (!files) {\n",
              "    return {\n",
              "      response: {\n",
              "        action: 'complete',\n",
              "      }\n",
              "    };\n",
              "  }\n",
              "\n",
              "  for (const file of files) {\n",
              "    const li = document.createElement('li');\n",
              "    li.append(span(file.name, {fontWeight: 'bold'}));\n",
              "    li.append(span(\n",
              "        `(${file.type || 'n/a'}) - ${file.size} bytes, ` +\n",
              "        `last modified: ${\n",
              "            file.lastModifiedDate ? file.lastModifiedDate.toLocaleDateString() :\n",
              "                                    'n/a'} - `));\n",
              "    const percent = span('0% done');\n",
              "    li.appendChild(percent);\n",
              "\n",
              "    outputElement.appendChild(li);\n",
              "\n",
              "    const fileDataPromise = new Promise((resolve) => {\n",
              "      const reader = new FileReader();\n",
              "      reader.onload = (e) => {\n",
              "        resolve(e.target.result);\n",
              "      };\n",
              "      reader.readAsArrayBuffer(file);\n",
              "    });\n",
              "    // Wait for the data to be ready.\n",
              "    let fileData = yield {\n",
              "      promise: fileDataPromise,\n",
              "      response: {\n",
              "        action: 'continue',\n",
              "      }\n",
              "    };\n",
              "\n",
              "    // Use a chunked sending to avoid message size limits. See b/62115660.\n",
              "    let position = 0;\n",
              "    do {\n",
              "      const length = Math.min(fileData.byteLength - position, MAX_PAYLOAD_SIZE);\n",
              "      const chunk = new Uint8Array(fileData, position, length);\n",
              "      position += length;\n",
              "\n",
              "      const base64 = btoa(String.fromCharCode.apply(null, chunk));\n",
              "      yield {\n",
              "        response: {\n",
              "          action: 'append',\n",
              "          file: file.name,\n",
              "          data: base64,\n",
              "        },\n",
              "      };\n",
              "\n",
              "      let percentDone = fileData.byteLength === 0 ?\n",
              "          100 :\n",
              "          Math.round((position / fileData.byteLength) * 100);\n",
              "      percent.textContent = `${percentDone}% done`;\n",
              "\n",
              "    } while (position < fileData.byteLength);\n",
              "  }\n",
              "\n",
              "  // All done.\n",
              "  yield {\n",
              "    response: {\n",
              "      action: 'complete',\n",
              "    }\n",
              "  };\n",
              "}\n",
              "\n",
              "scope.google = scope.google || {};\n",
              "scope.google.colab = scope.google.colab || {};\n",
              "scope.google.colab._files = {\n",
              "  _uploadFiles,\n",
              "  _uploadFilesContinue,\n",
              "};\n",
              "})(self);\n",
              "</script> "
            ]
          },
          "metadata": {}
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Saving Qasim CV - 20251505.pdf to Qasim CV - 20251505 (1).pdf\n",
            "Loaded 1 pages from Qasim CV - 20251505 (1).pdf\n",
            "Added 1 PDF pages to the knowledge base.\n",
            "Total documents in collection: 4\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "\n",
        "async def main_pdf_question():\n",
        "    # Ask a question that relates to the uploaded PDF content\n",
        "    pdf_question = \"Who is Muhammad Qasim\" # Replace with a specific question about your PDF\n",
        "\n",
        "    # Run the agent with the new question\n",
        "    result = await Runner.run(qa_agent, pdf_question)\n",
        "\n",
        "    # Extract and print the final answer\n",
        "    print(\"Agent result for PDF question:\", result)\n",
        "    print(\"Agent's answer for PDF question:\", result.final_output)\n",
        "\n",
        "if __name__ == \"__main__\":\n",
        "    asyncio.run(main_pdf_question())"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "MCHCSQgNr0bm",
        "outputId": "886293db-fc39-4ad5-9685-b716b858b27f"
      },
      "execution_count": 55,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[Debug] RAG function call with query Who is Muhammad Qasim\n",
            "[Debug] RAG vector db output {'ids': [['pdf_page_1']], 'embeddings': None, 'documents': [['Muhammad Qasim\\nChief Data Scientist at Cancer Clarity LLC | Honorary Chief Agentic AI Oﬃcer at PIAIC & GIAIC\\nm.qasim077@gmail.com | +923152968211 | linkedin.com/in/sirqasim | facebook.com/Ai.SirQasim\\nSummary\\nExpert in Agent-Native Cloud architectures, specializing in Dapr Agentic Cloud Ascent (DACA) design patterns\\nto build scalable, AI-driven systems. As Chief Data Scientist at Cancer Clarity LLC, I leverage agentic cloud\\ntechnologies like Dapr, OpenAI Agents SDK, and Kubernetes to advance cancer treatment solutions. As Honorary\\nChief Generative AI Oﬃcer at PIAIC and GIAIC, I mentor over 500,000 students in agentic AI and cloud-native\\nframeworks. Formerly a Data Scientist at UBL, I delivered AI solutions using Knowledge Graphs and cloud\\ninfrastructure. Proﬁcient in multi-agent systems, Generative AI, and Deep Learning, I drive innovation in\\nagentic cloud ecosystems.\\nProfessional Experience\\nChief Data Scientist, Cancer Clarity LLC New York, USA Apr 2022 – Present\\nAgent-Native Systems: Design agentic cloud architectures using Dapr and FastAPI to optimize API pipelines\\nfor cancer research.\\nCloud Integration : Implement MCP and Kubernetes to ensure scalable, standardized model interactions\\nacross healthcare systems.\\nChief AI Oﬃcer, Panacloud Pakistan Aug 2023 – Present\\nInnovation: Lead development of agent-native AI products with OpenAI Agents SDK, Dapr, and Azure\\nContainer Apps.\\nCloud Strategy : Architect scalable cloud solutions using Kubernetes and A2A protocols for real-time agentic\\nworkﬂows.\\nHonorary Chief Generative AI Oﬃcer, PIAIC & Governor Sindh Initiative Pakistan Aug 2023 –\\nPresent\\nEducation: Train 500,000+ students in Agent-Native Cloud frameworks, focusing on DACA and multi-agent\\nsystems.\\nLeadership: Spearhead GenAI and Web3 initiatives using agentic cloud technologies to drive innovation.\\nLead AI Instructor, Pakistan Blockchain Institute Pakistan Aug 2022 – Present\\nTraining: Deliver corporate training on Agent-Native Cloud, DACA, and AI, emphasizing practical cloud-\\nnative applications.\\nData Scientist, United Bank Limited Pakistan May 2018 – Apr 2022\\nAnalytics: Developed AI-driven ﬁnancial solutions using Knowledge Graphs and cloud-native data pipelines.\\nEducation\\nM.S. Data Science, National University of Computer and Emerging Sciences Karachi, Pakistan 2019\\n– 2021 B.S. Computer Science, Preston University Karachi, Pakistan 2013 – 2017\\nSkills\\n• Agent-Native Cloud : Dapr, OpenAI Agents SDK, Model Context Protocol (MCP), Agent2Agent (A2A),\\nDACA Design Patterns\\n• AI & Data Science : LangGraph, AutoGen, Custom GPTs, Deep Learning, Large Language Models, Knowl-\\nedge Graphs\\n• Frameworks & Tools : LangChain, CrewAI, FastAPI, Docker Compose, CI/CD, Serverless\\n• Cloud & Deployment : Kubernetes, Azure Container Apps, Serverless Containers\\n• Web Development: TypeScript, Next.js, GraphQL, REST, OpenAPI\\n• Databases: RDBMS, NoSQL, Graph Databases, Distributed Databases\\n• Certiﬁcations: Neo4j Certiﬁed Professional, ICAEW Data Analytics, Python Microsoft Certiﬁed\\n1']], 'uris': None, 'included': ['documents'], 'data': None, 'metadatas': None, 'distances': None}\n",
            "[Debug] RAG function call with response ***Muhammad Qasim is the Chief Data Scientist at Cancer Clarity LLC and Honorary Chief Generative AI Officer at PIAIC & GIAIC.  He is an expert in Agent-Native Cloud architectures, specializing in Dapr Agentic Cloud Ascent (DACA) design patterns.  He mentors over 500,000 students in agentic AI and cloud-native frameworks.  He previously worked as a Data Scientist at UBL.\n",
            "***\n",
            "Agent result for PDF question: RunResult:\n",
            "- Last agent: Agent(name=\"QA Agent\", ...)\n",
            "- Final output (str):\n",
            "    Muhammad Qasim is the Chief Data Scientist at Cancer Clarity LLC and Honorary Chief Generative AI Officer at PIAIC & GIAIC.  He is an expert in Agent-Native Cloud architectures, specializing in Dapr Agentic Cloud Ascent (DACA) design patterns.  He mentors over 500,000 students in agentic AI and cloud-native frameworks.  He previously worked as a Data Scientist at UBL. \n",
            "- 3 new item(s)\n",
            "- 2 raw response(s)\n",
            "- 0 input guardrail result(s)\n",
            "- 0 output guardrail result(s)\n",
            "(See `RunResult` for more details)\n",
            "Agent's answer for PDF question: Muhammad Qasim is the Chief Data Scientist at Cancer Clarity LLC and Honorary Chief Generative AI Officer at PIAIC & GIAIC.  He is an expert in Agent-Native Cloud architectures, specializing in Dapr Agentic Cloud Ascent (DACA) design patterns.  He mentors over 500,000 students in agentic AI and cloud-native frameworks.  He previously worked as a Data Scientist at UBL. \n",
            "\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "qWQn1cXqrsmA"
      },
      "execution_count": null,
      "outputs": []
    }
  ]
}